﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;
using jSLCore.Client.Presentation.jBinding;
using jSLCore.Client.Utility;

namespace jSLCore.Client.Presentation.BaseControl.Selection
{
    /// <summary>
    /// Наша реализация SL грида, что б он мог работать как ISelectableGrid, Dont use it virtualization with jValidationBinding or derived
    /// </summary>
    public class jSLGrid : DataGrid,ISelectableGrid
    {
        public jSLGrid()
        {
            //this.SelectedRows.CollectionChanged+=SelectedRowsOnCollectionChanged;
            base.SelectionChanged += OnSelectionChanged;
           /* LoadingRow+=OnLoadingRow;*/
            UnloadingRow+=OnUnloadingRow;
            LoadingRow += OnloadingRow;

            _singleSelectColumn.RowSelected += OnSingleSelectColumnOnRowSelected;


            _multiSelectColumn.RowSelected += OnMultiSelectColumnOnRowSelected;
            _multiSelectColumn.RowUnselected += OnMultiSelectColumnOnRowUnselected;
            _multiSelectColumn.CheckBox_Loaded += OnMultiSelectColumnOnCheckBoxLoaded;
           
            _showDetailsColumn.CellClick+=ShowDetailsColumnOnCellClick;

            Columns.Add(_singleSelectColumn);
            Columns.Add(_multiSelectColumn);
            Columns.Add(_showDetailsColumn);

            AutoGenerateColumns=false;

            Loaded += (sender, args) =>
                          {
                              _baseControl = FindBaseControl();
                          };

            DefaultStyleKey = typeof (DataGrid);

        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                if (SelectionMode == GridSelectionMode.SingleRow)
                {
                    var selectedRows = GetSelectedRows();

                    if (selectedRows.Length > 0)
                    {
                        InvokeRowSelected(new RowSelectedEventArgs(selectedRows[0]));
                    }
                    e.Handled = true;
                }
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                if (SelectionMode == GridSelectionMode.SingleRow)
                {
                    var selectedRows = GetSelectedRows();

                    e.Handled = true;//защищаемся от перехода на след. строку - ждем пепехода
                }
            }
        }

        public event EventHandler<RowSelectedEventArgs> ShowDetailsClicked;

        public void InvokeShowDetailsClicked(RowSelectedEventArgs e)
        {
            EventHandler<RowSelectedEventArgs> handler = ShowDetailsClicked;
            if (handler != null) handler(this, e);
            else
            {
                throw new NotImplementedException("You have to implement ShowDetailsClicked event");
            }
        }

        private void ShowDetailsColumnOnCellClick(object sender, RowSelectedEventArgs rowSelectedEventArgs)
        {
            InvokeShowDetailsClicked(rowSelectedEventArgs);
        }

        private void OnUnloadingRow(object sender, DataGridRowEventArgs dataGridRowEventArgs)
        {
            var bounds = jValidationBinding.BindControls;
            var quick = bounds.Where(b=>b.Key.CurrentDataContext==dataGridRowEventArgs.Row.DataContext);
            var low = quick.Where(b=>b.Key.UIElement!=null && b.Key.UIElement.IsImplicitParent(this)).ToArray();


            foreach (var b in low)//Тут конкретизируем поиск
            {
                b.Key.Unbind();
                if (b.Key is jValidationBinding)
                {
                    ((jValidationBinding) b.Key).FromData();
                    //b.Key.Kill();
                    ((jValidationBinding)b.Key).SetFirstError(null);
                }
                else
                {
                    //b.Key.Unbind();
                }
                
                if(!rows.ContainsKey(b.Key))
                rows.Add(b.Key,dataGridRowEventArgs.Row);
                //b.Key.Kill();//Убиваем, ибо в след раз для этого контрола будет назначена новая привязка. оказывается не будет
            }
        }

        private Dictionary<JBindingBase,DataGridRow> rows = new Dictionary<JBindingBase, DataGridRow>(10);

        private void OnloadingRow(object sender, DataGridRowEventArgs e)
        {
            IEnumerable<JBindingBase> keyValuePairs = rows.Where(r=>r.Value==e.Row).Select(r=>r.Key);

            

            var low =
                jValidationBinding.BindControls //Берем все привязки
                .Where(b=>keyValuePairs.Contains(b.Key) /*|| !rows.ContainsValue(e.Row)*/) //Если У нас уже был такой e.Row, то ищем бинбинги этого Row, иначе он не должен сюда попасть
                .Where(b => b.Key.BaseControl == _baseControl) //Теперь полученные фильруем по BaseControl... то есть берем все, которые находятся в этой BaseControl
                /*.Where(b => b.Key.UIElement != null && b.Key.UIElement.IsImplicitParent(e.Row))*///поиск не уточняем
                .ToArray();

            foreach (var b in low)
            {
                b.Key.Bind();
            }
        }

        private BaseControl FindBaseControl()
        {
            return this.FindAncestor<BaseControl>();
        }

        private void OnMultiSelectColumnOnCheckBoxLoaded(object sender2, EventArgs args1)
        {
            var checkBox = sender2 as CheckBox;
            if (checkBox != null)
               /* if (IsObjectsEquals != null)
                {*/
                  //  Dispatcher.BeginInvoke(() =>
                                                                 {
                                                                     var dataCont = checkBox.DataContext;

                                                                     var SOrDef = SelectedRows.SingleOrDefault(sr=>
                                                                         sr==dataCont ||
                                                                         (IsObjectsEquals != null && IsObjectsEquals(sr,dataCont)));
                                                                     
                                                                         if(SOrDef!=null)
                                                                         {
                                                                             checkBox.IsChecked = true;
                                                                         }
                                                                         else
                                                                         {
                                                                             checkBox.IsChecked = false;
                                                                         }
                                                                     

                                                                    /* for (int index = 0; index < SelectedRows.Count; index++)
                                                                     {
                                                                         var selRow = SelectedRows[index];

                                                                         var dataCont = checkBox.DataContext;

                                                                         if (selRow==dataCont || IsObjectsEquals(selRow, dataCont))
                                                                         {
                                                                           //  SelectedRows.RemoveAt(index);
                                                                             //SelectedRows.Insert(index, dataCont);
                                                                             checkBox.IsChecked = true;
                                                                             break;
                                                                         }
                                                                         else
                                                                         {
                                                                             checkBox.IsChecked = false;
                                                                         }
                                                                     }*/
                                                                 }//);
                    
                    
              //  }
        }

        private void OnMultiSelectColumnOnRowUnselected(object o1, RowSelectedEventArgs rowSelectedEventArgs)
        {
            if (SelectedRows.Contains(rowSelectedEventArgs.RowObject))
            {
                SelectedRows.Remove(rowSelectedEventArgs.RowObject);
                InvokeSelectionChanged(EventArgs.Empty);
            }
        }

        private void OnMultiSelectColumnOnRowSelected(object sender1, RowSelectedEventArgs selectedEventArgs)
        {
            
            if (!SelectedRows.Contains(selectedEventArgs.RowObject))
            {
               /* var checkAccess = Dispatcher.CheckAccess();
                Dispatcher.BeginInvoke(() =>
                                           {*/
                                               SelectedRows.Add(selectedEventArgs.RowObject);
                                               InvokeSelectionChanged(EventArgs.Empty); 
               //                            });
                
            }
        }

        public bool IsShowDetailsButtonVisible
        {
            get { return _showDetailsColumn.Visibility ==  System.Windows.Visibility.Visible; }
            set { _showDetailsColumn.Visibility = value ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed; }
        }

        private void OnSingleSelectColumnOnRowSelected(object o, RowSelectedEventArgs eventArgs)
        {
            InvokeRowSelected(new RowSelectedEventArgs(eventArgs.RowObject));
        }

        private void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
        {
            if (SelectionMode == GridSelectionMode.SingleRow)
            {
                InvokeSelectionChanged(EventArgs.Empty);
            }
        }

        protected ObservableCollection<object> SelectedRows = new ObservableCollection<object>();
        
        /// <summary>
        /// Определяем этот делегат, если хотим, что бы при смене DataSource, выбранные объекты оставались в кэше, и при повторном показе чек боксы уже были выбраны
        /// </summary>
        public static IsObjectsEqualsDelegate IsObjectsEquals { get; set; }

        /// <summary>
        /// Очищает выбранные записи. Не производит визуальных изменений
        /// </summary>
        public void ClearSelectedRows()
        {
            SelectedRows.Clear();
        }
        
        public new IEnumerable ItemsSource
        {
            get { return base.ItemsSource; }
            set
            {
                base.ItemsSource = value;
                if(IsObjectsEquals==null)
                {
                    SelectedRows.Clear();
                }
            }
        }

        private SingleSelectColumn _singleSelectColumn = new SingleSelectColumn() { CanUserResize = false, CanUserReorder = false, CanUserSort = false, DisplayIndex = 0, Visibility = System.Windows.Visibility.Collapsed };

        private MultiSelectColumn _multiSelectColumn = new MultiSelectColumn()
                                                           {
                                                               CanUserReorder = false,
                                                               CanUserResize = false,
                                                               CanUserSort = false,
                                                               DisplayIndex = 1,
                                                               Visibility = System.Windows.Visibility.Collapsed
                                                           };

        private ShowDetailsColumn _showDetailsColumn = new ShowDetailsColumn() { Visibility = System.Windows.Visibility.Collapsed, DisplayIndex = 2 };

        public object[] GetSelectedRows()
        {
            if (SelectionMode == GridSelectionMode.SingleRow || SelectionMode == GridSelectionMode.None)
            {
                if (SelectedItems.Count == 0) return new object[0];

                return SelectedItems.Cast<object>().ToArray();
            }

            if (SelectionMode == GridSelectionMode.MultiRow)
            {
                if (SelectedRows.Count == 0) return new object[0];
                return SelectedRows.ToArray();
            }

            return new object[0];
        }

        
        private bool isSelectable;
        private BaseControl _baseControl;


        private bool IsSelectable
        {
         get
         {
             return isSelectable;
         }
            set
            {
                isSelectable = value;
            }
        }
        public new GridSelectionMode SelectionMode
        {
            get
            {
                if(!IsSelectable)return GridSelectionMode.None;

                if (_singleSelectColumn.Visibility == System.Windows.Visibility.Visible) return GridSelectionMode.SingleRow;
                if (_multiSelectColumn.Visibility == System.Windows.Visibility.Visible) return GridSelectionMode.MultiRow;
                
                return GridSelectionMode.None;
            }
            set
            {
                switch (value)
                {
                    case GridSelectionMode.None:
                        IsSelectable = false;
                        _singleSelectColumn.Visibility = System.Windows.Visibility.Collapsed;
                        _multiSelectColumn.Visibility = System.Windows.Visibility.Collapsed;
                        break;

                        case GridSelectionMode.SingleRow:
                        base.SelectionMode = DataGridSelectionMode.Single;
                        IsSelectable = true;
                        _singleSelectColumn.Visibility = System.Windows.Visibility.Visible;
                        _multiSelectColumn.Visibility = System.Windows.Visibility.Collapsed;
                        break;

                        case GridSelectionMode.MultiRow:
                        base.SelectionMode = DataGridSelectionMode.Single;
                        IsSelectable = true;
                        _singleSelectColumn.Visibility = System.Windows.Visibility.Collapsed;
                        _multiSelectColumn.Visibility = System.Windows.Visibility.Visible;
                        break;
                }
            }
        }



        public new event EventHandler SelectionChanged;
        private void InvokeSelectionChanged(EventArgs e)
        {
            var temp = SelectionChanged;
            if (temp != null) temp(this, e);
        }

       
        public event EventHandler<RowSelectedEventArgs> RowSelected;
        private void InvokeRowSelected(RowSelectedEventArgs e)
        {
            EventHandler<RowSelectedEventArgs> selected = RowSelected;
            if (selected != null) selected(this, e);
        }
    }
}